/*
 * BSM6.0
 *
 * Copyright 2012-2013 (C) SINODATA CO., LTD. All Rights Reserved.
 */
package com.sinodata.bsm.center.engine.property;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;

import com.sinodata.bsm.center.cache.PropertyCache;
import com.sinodata.bsm.center.dao.PropertyValueDao;
import com.sinodata.bsm.center.dao.impl.PropertyValueDaoImpl;
import com.sinodata.bsm.center.util.spring.SpringContextHolder;
import com.sinodata.bsm.common.constants.SeparatorConstants;
import com.sinodata.bsm.common.vo.Property;
import com.sinodata.bsm.common.vo.ResPropertyValue;

/**
 * <p>
 * Description: 
 * </p>
 *
 * @author tangli
 * @version 1.0

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2012-6-14 下午2:56:50          tangli         1.0         To create
 * </p>
 *
 * @since 
 * @see     
 */
public class PropertyValuePersistentThread extends Thread {
    private final static Logger logger = Logger.getLogger(PropertyValuePersistentThread.class);
    private static PropertyValuePersistentThread instance = new PropertyValuePersistentThread();
    private LinkedBlockingQueue<ResPropertyValue> queue = new LinkedBlockingQueue<ResPropertyValue>();
    private PropertyCache propertyCache = SpringContextHolder.getBean(PropertyCache.class);
    private PropertyValueDao dao = SpringContextHolder.getBean(PropertyValueDaoImpl.class);
    private final static Pattern pattern = Pattern.compile("^-?\\d*(?:.\\d+)?(?:(?:[Ee]-?\\d+)|[lLdDfF])?$");

    /**
     * 
     */
    private PropertyValuePersistentThread() {
        this.start();
    }

    public static PropertyValuePersistentThread getInstance() {
        return instance;
    }

    public void add(ResPropertyValue value) {
        queue.add(value);
    }

    public void run() {
        while (true) {
            Long timeMillis = System.currentTimeMillis();
            List<ResPropertyValue> list = new ArrayList<ResPropertyValue>();
            queue.drainTo(list);
            if (list.size() > 0) {
                List<Map<String, Object>> values = new ArrayList<Map<String, Object>>();
                for (ResPropertyValue value : list) {
                    Map<String, Object> map = pack(value);
                    values.add(map);
                }
                try {
                    dao.insert(values);
                } catch (Exception e) {
                    e.printStackTrace();
                    logger.error(e);
                }
            }
            if (System.currentTimeMillis() - timeMillis < 60000L) {
                try {
                    Thread.sleep(60000L - (System.currentTimeMillis() - timeMillis));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private Map<String, Object> pack(ResPropertyValue value) {
        ResPropertyValue.PropValue[] propValues = value.getValues();
        Map<String, Object> valueMap = new HashMap<String, Object>();
        valueMap.put("RESID", value.getResId());
        valueMap.put("TIME", value.getTime());
        for (ResPropertyValue.PropValue propValue : propValues) {
            Property prop = propertyCache.get(propValue.propId);
            int storeId;
            if (prop == null || (storeId = prop.getStore()) <= 0 || propValue.value == null)
                continue;
            if (prop.getDataTypeId() == 4L) {
                valueMap.put("PROP" + storeId, "OBJECT...");
                String[] rows = propValue.value.split(SeparatorConstants.LIN_SEPARATOR);
                for (int i = 0; i < rows.length; i++) {
                    String[] columns = rows[i].split(SeparatorConstants.COL_SEPARATOR);
                    Object[] data = new Object[24];
                    data[0] = value.getResId();
                    data[1] = propValue.propId;
                    data[2] = value.getTime();
                    System.arraycopy(columns, 0, data, 3, columns.length > 20 ? 20 : columns.length);
                    PropertyValueObjectPersistentThread.getInstance().add(data);
                }
            } else if (prop.getDataTypeId() == 6L) {
                //大字段类型
                valueMap.put("PROP" + storeId, "Clob...");
                Object[] data = new Object[24];
                data[0] = value.getResId();
                data[1] = propValue.propId;
                data[2] = value.getTime();
                data[23] = propValue.value;
                PropertyValueObjectPersistentThread.getInstance().add(data);
            } else if (prop.getDataTypeId() == 2) {
                try {
                    if ("NaN".equals(propValue.value) || "N/A".equals(propValue.value) || "".equals(propValue.value)) {
                        continue;
                        //propValue.value = "0";
                    } else {
                        if (!pattern.matcher(propValue.value).find()) {
                            continue;
                        }
                        //lLdDfF
                        char lastChar = propValue.value.charAt(propValue.value.length() - 1);
                        if (lastChar > '9' || lastChar < '0') {
                            propValue.value = propValue.value.substring(0, propValue.value.length() - 1);
                        }
                    }
                    valueMap.put("PROP" + storeId, propValue.value);
                } catch (Exception e) {
                    logger.error("failed to call " + this.getClass().getName() + ".putHistPorps", e);
                }
            } else {
                if (propValue.value.length() > 256) {
                    propValue.value = propValue.value.substring(0, 255);
                }
                valueMap.put("PROP" + storeId, propValue.value);
            }
        }
        return valueMap;
    }
}
